虽说指针是C语言中比较复杂的语法,但是确实非常好用,因此我写过不少文章讨论C语言中的指针,相信对初学者理解指针有一定的帮助。
事实上,的确有读者私信我说看了这些文章,“总算不再畏惧指针了”。不过他同时也问了一个问题:C语言有“不透明指针(opaque pointer)”吗?要是有的话,什么样的指针才是不透明指针呢,有什么用呢?
C语言的“不透明指针”
坦诚地说,我比较讨厌向初学者说一些非常“专业”的名词,这不利于理解概念的本质,也容易让一些初学者产生畏惧的心理。“不透明指针”就是其中之一,其实它并不是多难的概念,甚至都不是什么新概念,只是一些基本知识的用法而已,只不过取了个非常装x的名字。
从字面意思来看,“不透明”意味着看不到内部,因此“不透明指针”即看不到内部定义的指针。这样说有些抽象,我们来看个例子:
typedef struct pmpi_s *pmpi;
上面这行C语言代码使用 typedef 关键字定义了一个结构体指针类型 pmpi,结构体由 pmpi_s 指定。虽然还没有具体定义结构体 pmpi_s,但是已经可以使用 pmpi 定义变量了,例如下面这行C语言代码:
pmpi p = NULL;
这里的指针 p 就是一个“不透明指针”,因为我们暂时看不到它到底指向什么样的内容,就像一个“不透明”的盒子一样。
就像一个“不透明”的盒子一样
到这里,相信读者已经明白什么是C语言中的“不透明指针”了,而且也能看出,所谓的“不透明指针”其实并不是什么新概念,它不过是为了便于描述特定类型指针,方便同行之间交流取的名字而已。
一般来说,稍大的C语言项目都不是一个人开发的,在多人协作开发中,少不了要调用别人编写的库函数,或者要把自己编写的库函数提供给别人使用。
即使是初学者也应该明白,要调用C语言函数,首先需要知道它的原型,因此通常情况下,库一般都会提供头文件,头文件里包含库里实现的函数原型或者数据结构的定义。例如我们常用的
可是,有时我并不希望将我编写的库所有细节公开给外界调用者。例如在源代码中,有这样的定义,相关C语言代码如下,请看:
// fun.c 文件 ... struct pmpi_s { uint16_t *data; size_t sz; size_t used; int sign; }; void handle_s(struct pmpi_s *p){ ... } ...
我只想在我自己的源文件(.c 文件)里使用结构体 pmpi_s,而不希望外界调用者知道它的结构,从而轻易的修改相关数据。通常情况下,只要不把这个定义写在对外公开的头文件里就可以了。但是,如果 handle_s() 也是需要公开的库函数其中一个,那么我将不得不提供 pmpi 结构体的定义,这样看来,似乎不能两全了?
当然不是,此时C语言的“不透明指针”就派上用场了,在头文件里放入结构体 pmpi 的不透明指针:
// fun.h 文件
typedef struct pmpi_s *pmpi;
void handle_s(pmpi p);
C语言的“不透明指针”
这样一来,如果我的同事需要调用我编写库函数时,只需要包含 "fun.h" 就可以了,他能够使用 handle_s() 函数,但是他不知道 pmpi_s 的具体结构,因为这是我想隐藏的内容。
小结
C语言的语法其实很精简,一些看似复杂的概念(例如“不透明指针”)其实只是对基本概念的引用而已,透明指针可以隐藏库的一些细节,一是为了安全,二是为了便于以后扩展——无论我在我的库内如何修改 pmpi_s 结构体,也不会影响到外界的调用者。
其实就本文的例子,我们完全可以使用“万能指针(void * 指针)”隐藏相关细节,这一点我之前的文章讨论过,不再赘述了。
本页共60段,2119个字符,4691 Byte(字节)